package com.lenovo.nova.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;

import com.lenovo.nova.util.Applications.OnInputModeChangeListener;
import com.lenovo.nova.util.Applications.OnTouchBoardTouchedListener;
import com.lenovo.nova.util.Constant.Debug;
import com.lenovo.nova.util.debug.MyOldLog;
import com.lenovo.nova.util.debug.mylog;
import com.lenovo.nova.util.debug.slog;
import com.lenovo.nova.util.view.KeyUtil;
import com.lenovo.nova.utils.R;

@SuppressLint("NewApi")
public class CustomListView extends ListView implements OnTouchBoardTouchedListener, OnScrollListener, OnInputModeChangeListener {

    private boolean mDebugMode;
    private int mItemIndex;
	private int mSmoothIndex;
	// 如果需要setselection的时候，如果没有onLayout ,需要使用setSlectoinFromTop（index ，0）
	// protected int mItemAndDivideHeight = 99;
	protected int mItemAndDivideHeight = 0;

	private int mOnePageShowItemCount = -1;

	public static final int ARROW_DOWN = VerticalArrowBuilderHelper.CLICK_ARROW_DOWN;
	public static final int ARROW_UP = VerticalArrowBuilderHelper.CLICK_ARROW_UP;

	private static final String TAG = "CustomListView";

	private int mItemCount;

	private HelperForAbsListViewOnHover mUiHelper = null;

	private VerticalArrowBuilderHelper mArrowHelper;
    private Drawable mTopArrowDrawable;
    private Drawable mBottomArrowDrawable;

    private Drawable mHoverDrawable;

    public CustomListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initLayout();
	}

	public CustomListView(Context context, AttributeSet attrs) {
		super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomListView);
        mOnePageShowItemCount = a.getInt(R.styleable.CustomListView_OnePageItemNumber,-1);
        mTopArrowDrawable = a.getDrawable(R.styleable.CustomListView_topArrowDrawable);
        mBottomArrowDrawable = a.getDrawable(R.styleable.CustomListView_bottomArrowDrawable);
        mHoverDrawable = a.getDrawable(R.styleable.CustomListView_hoverDrawable);

        initLayout();
    }

    public CustomListView(Context context) {
		super(context);
		initLayout();
	}

    @Override
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(adapter);
        adapter.registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                slog.p(TAG, TAG + " registerDataSetObserver onChanged " + getChildCount() + "   " + getCount());
            }

            @Override
            public void onInvalidated() {
                slog.p(TAG, TAG + " registerDataSetObserver onInvalidated " + getChildCount() + "   " + getCount());
                if (mArrowHelper != null) {
                    mArrowHelper.onInvalidated();
                }
            }
        });
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        MyOldLog.p(Debug.METHOD_TAG, "onAttachedToWindow");
        SettingsApplication.get().addOnTochBoardTouchedListener(this);
        SettingsApplication.get().addOnInputModeChangeListener(this);

        if(mArrowHelper != null){
            mArrowHelper.onAttachedToWindow();
        }

        if(mTopArrowDrawable != null){
            mArrowHelper.setTopArrowDrawable(mTopArrowDrawable);
        }

        if(mBottomArrowDrawable != null){
            mArrowHelper.setBottomArrowDrawable(mBottomArrowDrawable);
        }

        waitForSetListViewHeight();
    }

    @SuppressLint("NewApi")
    @Override
    protected void onDetachedFromWindow() {
        MyOldLog.p(Debug.METHOD_TAG, "onDetachedFromWindow");
        if(mArrowHelper != null){
            mArrowHelper.onDetachedFromWindow();
        }
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
        SettingsApplication.get().removeOnInputChangeListener(this);
        SettingsApplication.get().removeOnTouchBoardListener(this);
        super.onDetachedFromWindow();
    }

    @Override
    public int getSelectedItemPosition() {
        return getItemIndex();
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (onCommonKey(keyCode, event)) {
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_A) {
            Log.d("NovaSettings", "keycode : first" + getFirstVisiblePosition() + " end" + getLastVisiblePosition());
        }
        if (keyCode == KeyEvent.KEYCODE_C) {
            arrow(ARROW_UP);
        }
        if (keyCode == KeyEvent.KEYCODE_D) {
            arrow(ARROW_DOWN);
        }
        if (keyCode == KeyEvent.KEYCODE_B) {
            Log.d("NovaSettings", "keycode : first" + getFirstVisiblePosition() + " end" + getLastVisiblePosition());
            View firstView = this.getChildAt(0);
            Log.d("NovaSettings", " first re" + firstView.getY());

            printView(firstView, "first");
            View endView = this.getChildAt(getChildCount() - 1);
            printView(endView, "end");
            printView(this, "this");
            // arrow(ARROW_UP);
        }
        if (onCommonKey(keyCode, event)) {
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public void onGlobalLayout() {
        super.onGlobalLayout();
        mylog.d(TAG, "onGlobalLayout initialized ");
        // onGlobalLayout be called many times, but initArrow just be call once
        if(mArrowHelper != null){
            boolean isVisibleToUser = isVisibleToUser();
            mArrowHelper.onGlobalLayout(isVisibleToUser);
        }

    }

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		super.onScrollChanged(l, t, oldl, oldt);
		mylog.d(TAG, "onScrollChanged");
		if (mArrowHelper != null) {
			mArrowHelper.onScrollChanged(l, t, oldl, oldt);
		}

		if (mUiHelper != null) {
			mUiHelper.onScrollChanged(l, t, oldl, oldt);
		}
	}

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        slog.d(TAG, "onScrollStateChanged scrollState " + scrollState);
    }

    @Override
    public boolean onHoverEvent(MotionEvent event) {
        if (mUiHelper.onHoverEvent(event)) {
            return true;
        }

        return super.onHoverEvent(event);
    }

    @Override
    public void onHoverChanged(boolean hovered) {
        super.onHoverChanged(hovered);
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        // final String tag = "onFocusChanged.CustomListView";
        slog.p(TAG, "onFocusChanged " + gainFocus + "  " + direction + "  " + previouslyFocusedRect);
        if(mUiHelper != null){
            mUiHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        }

        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
    }

    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
        return false ;
    }

    @Override
    protected boolean dispatchHoverEvent(MotionEvent event) {
        return super.dispatchHoverEvent(event);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mylog.d(TAG, "onScroll firstVisibleItem " + firstVisibleItem + "  visibleItemCount " + visibleItemCount + "  totalItemCount" + totalItemCount);
        mSmoothIndex = firstVisibleItem;
        if(mArrowHelper != null){
            mArrowHelper.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mUiHelper != null) {
            mUiHelper.draw(canvas);
        }

        super.onDraw(canvas);
    }

    @SuppressLint("WrongCall")
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        int mViewHeight = b - t;
        if (getChildAt(0) != null) {
            mItemAndDivideHeight = getChildAt(0).getHeight() + getDividerHeight();
            slog.p(TAG, "onLayout mItemAndDivideHeight is " + mItemAndDivideHeight);
        }

        calcOnePageShowItemCountIfNeed(mViewHeight);

        if(mArrowHelper != null){
            mArrowHelper.onLayout(changed, l, t, r, b);
        }
    }

    @Override
    public void setSelection(int position) {
        if (mOnePageShowItemCount <= 0) {
            // call super before onLayout be called
            super.setSelection(position);
        } else {
            // 果需要setselection的时候，如果没有onLayout ,需要使用setSlectoinFromTop（index ，0）
            // we can get itmeFromTopDistance only after onLayout
            int itmeFromTopDistance = mItemAndDivideHeight * (position % mOnePageShowItemCount);
            setSelectionFromTop(position, itmeFromTopDistance);
            mItemIndex = position;
        }
    }

    @Override
    public void onTouchBoardTouched(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (KeyUtil.isTouchBoardUp(event.getKeyCode())) {
                nextSmoothScroll();
            }
            if (KeyUtil.isTouchBoardDown(event.getKeyCode())) {
                lastSmoothScroll();
            }
        }
    }

    @Override
    public void onInputModeChange(boolean isInTouchMode) {
        if (mUiHelper != null) {
            mUiHelper.onInputModeChange(isInTouchMode);
        }
    }

    public boolean isInDebugMode(){
        return mDebugMode;
    }

    public void setTopArrowDrawable(Drawable drawable){
        mTopArrowDrawable = drawable;
    }

    public void setBottomArrowDrawable(Drawable drawable){
        mBottomArrowDrawable = drawable;
    }

    protected void waitForSetListViewHeight() {
        if (mOnePageShowItemCount != -1) {
            post(new Runnable() {
                @Override
                public void run() {
                    View firsView = getChildAt(0);
                    if (firsView == null) {
                        mylog.i(TAG, "wait CustomList get the child");
                        postDelayed(this, 10);
                        return;
                    }
                    int itemHeight = firsView.getHeight();
                    int listHeight = getDividerHeight() * (mOnePageShowItemCount - 1) + itemHeight * mOnePageShowItemCount;
                    setDimension(-1, listHeight);

                    mylog.i(TAG, "OnePage number is " + mOnePageShowItemCount +
                            " item width " + itemHeight +
                            " listHeight " + listHeight +
                            "listWidth " + getWidth()
                    );
                }
            });
        }
    }

    private void calcOnePageShowItemCountIfNeed(int mViewHeight) {
        if(mOnePageShowItemCount == - 1){
            if (mItemAndDivideHeight != 0 && mViewHeight % mItemAndDivideHeight == 0) {
                mOnePageShowItemCount = (mViewHeight / mItemAndDivideHeight);
            } else {
                if (mItemAndDivideHeight != 0) {
                    mOnePageShowItemCount = (mViewHeight / mItemAndDivideHeight) + 1;
                }
            }
        }
    }

    public int getItemIndex() {
        return mItemIndex;
    }

	public void arrow(int direction) {
		switch (direction) {
		case ARROW_DOWN:
			nextSmoothScroll();
			break;
		case ARROW_UP:
			lastSmoothScroll();
			break;
		default:
			break;
		}
	}

    public void notifyNeedInitArrow() {
        if(mArrowHelper != null){
            mArrowHelper.notifyNeedInitArrow();
        }
    }

	public boolean onCommonKey(int keyCode, KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_DOWN) {
			mItemCount = getCount();
			if (KeyUtil.isDown(keyCode) || KeyUtil.isUp(keyCode)) {
				switch (keyCode) {
				case KeyEvent.KEYCODE_DPAD_DOWN:
					if (mItemIndex < mItemCount - 1) {
						mItemIndex++;
					} else {
						return super.onKeyDown(keyCode, event);
					}
					break;
				case KeyEvent.KEYCODE_DPAD_UP:
					if (mItemIndex > 0) {
						mItemIndex--;
					} else {
						return super.onKeyDown(keyCode, event);
					}
					break;
				}
				setSelection(mItemIndex);
				return true;
			}
		}
		return false;
	}

	public void setDimension(int width, int height) {
		ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) getLayoutParams();
		if (width >= 0) {
			params.width = width;
		}
		if (height >= 0) {
			params.height = height;
		}
		setLayoutParams(params);
	}

	public void nextSmoothScroll() {

		mArrowHelper.nextSmoothScroll();
	}

	public void lastSmoothScroll() {

		mArrowHelper.lastSmoothScroll();
	}

    protected Drawable getHoverDrawable() {
        if(mHoverDrawable != null){
            return mHoverDrawable;
        }
        return new ColorDrawable(Color.YELLOW);
    }

    public void setTopArrowOffSet(int i) {
        mArrowHelper.setTopArrowOffSet(i);
    }

    private void printView(View view, Object... obj) {
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        Log.d("NovaSettings",
                "x:" + location[0] + " y:" + location[1] + "   " + obj[0] + " height:" + view.getHeight() + " padBo" + view.getPaddingBottom() + "  padTop" + view.getPaddingTop()
                        + " mItemAndDivideHeight " + mItemAndDivideHeight);
    }

    public void setBottomArrowOffSet(int i) {
        mArrowHelper.setBottomArrowOffSet(i);
    }

//	private boolean isInTochMode() {
//		return SettingsApplication.get().isInTouchMode();
//	}

    private void initLayout() {
        // 增加该接口监听，检测onScroll函数，以便于滚动的时候初始化 mSmoothIndex
        setOnScrollListener(this);

        Drawable mHoverDrawable = getHoverDrawable();
        mUiHelper = new HelperForAbsListViewOnHover(this);
        mUiHelper.setHoverDrawable(mHoverDrawable);
        mArrowHelper = new VerticalArrowBuilderHelper(this);
    }



}
